package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type Image struct {
	Title    string `json:"title"`
	Desc     string `json:"desc"`
	Location string `json:"location"`
	Url      string `json:"url"`
}

func StoreJsonFileToDB(db *gorm.DB) {
	imageList := []Image{}
	fp, err := os.Open("./data.json")
	if err != nil {
		fmt.Println(err)
		return
	}
	raw, err := ioutil.ReadAll(fp)
	if err != nil {
		fmt.Println(err)
		return
	}
	err = json.Unmarshal(raw, &imageList)
	if err != nil {
		fmt.Println(err)
		return
	}
	db.Create(&imageList)
}

func UpdateImageUrl(db *gorm.DB, item Image) {
	db.Model(&Image{}).Where("title = ? and `desc` = ? and location = ?", item.Title, item.Desc, item.Location).Update("url", item.Url)
}

func SolveImageUrl(db *gorm.DB) {
	imageList := []Image{}
	db.Find(&imageList)
	for _, item := range imageList {
		// fmt.Printf("%#v\n", item)
		re, _ := regexp.Compile(`url\("(.*?)"\)`)
		repl := re.ReplaceAllString(item.Url, "$1")
		item.Url = repl
		UpdateImageUrl(db, item)
	}
}

func GetDB() (*gorm.DB, error) {
	dsn := "root:111111@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	db.AutoMigrate(&Image{})
	if err != nil {
		return nil, err
	}
	return db, nil
}

func DownloadImage(url, path string) (string, error) {
	res, err := http.Get(url)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()
	if fileInfo, ok := res.Header["Content-Disposition"]; ok {
		re, _ := regexp.Compile(`filename="(.*?)";`)
		fileName := re.ReplaceAllString(re.FindString(fileInfo[0]), "$1")
		if fileName != "" {
			raw, err := ioutil.ReadAll(res.Body)
			if err != nil {
				return "", err
			}
			err = ioutil.WriteFile(path+fileName, raw, 0644)
			if err != nil {
				return "", err
			}
			return fileName, nil
		} else {
			return "", errors.New("parse fileName error")
		}
	} else {
		return "", errors.New("parse fileName error")
	}
}

func DownloadImagesTask(db *gorm.DB) {
	imageList := []Image{}
	db.Find(&imageList)
	for _, item := range imageList {
		if fileName, err := DownloadImage(item.Url, "./images/"); err == nil {
			db.Model(&Image{}).Where("title = ? and `desc` = ? and location = ?", item.Title, item.Desc, item.Location).Update("url", fileName)
		} else {
			fmt.Println(err)
			continue
		}
	}
}

type StsInfo struct {
	Endpoint        string
	AccessKeyId     string
	AccessKeySecret string
	SecurityToken   string
	BucketName      string
}

func UploadToAliOss(info StsInfo, fileName string) error {
	client, err := oss.New(info.Endpoint, info.AccessKeyId, info.AccessKeySecret, oss.SecurityToken(info.SecurityToken))
	if err != nil {
		return err
	}
	bucket, err := client.Bucket(info.BucketName)
	if err != nil {
		return err
	}
	dir := time.Now().Format("2006/01/02/")
	fp, err := os.Open("./images/" + fileName)
	if err != nil {
		return err
	}
	raw, err := ioutil.ReadAll(fp)
	if err != nil {
		return err
	}
	err = bucket.PutObject(dir+fileName, bytes.NewReader(raw))
	if err != nil {
		return err
	}
	return nil
}

type HttpResult struct {
	Code      int      `json:"code"`
	Message   string   `json:"message"`
	Data      HttpData `json:"data"`
	Timestamp string   `json:"timestamp"`
}

type HttpData struct {
	AccessKeyId     string `json:"accessKeyId"`
	AccessKeySecret string `json:"accessKeySecret"`
	SecurityToken   string `json:"securityToken"`
	Region          string `json:"region"`
	Bucket          string `json:"bucket"`
	Uuid            string `json:"uuid"`
}

func GetTokenAndUploadImage(imageInfo *Image) error {
	req, err := http.NewRequest("GET", "http://localhost:7000/image-serv/file/token", nil)
	if err != nil {
		return err
	}
	req.Header.Set("Authorization", "Bearer 6d33fcd47f114bd49aa0083acde4f23f")
	res, err := (&http.Client{}).Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	raw, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return err
	}
	var hr HttpResult
	err = json.Unmarshal(raw, &hr)
	if err != nil {
		return err
	}
	si := StsInfo{
		Endpoint:        hr.Data.Region + ".aliyuncs.com",
		AccessKeyId:     hr.Data.AccessKeyId,
		AccessKeySecret: hr.Data.AccessKeySecret,
		SecurityToken:   hr.Data.SecurityToken,
		BucketName:      hr.Data.Bucket,
	}
	err = UploadToAliOss(si, imageInfo.Url)
	if err != nil {
		return err
	}
	dir := time.Now().Format("2006/01/02/")
	fileUrl := fmt.Sprintf("https://%s.%s/%s", si.BucketName, si.Endpoint, dir+imageInfo.Url)
	imageInfo.Url = fileUrl
	return nil
}

func UploadImageAndUpdateDbTask() {
	db, err := GetDB()
	if err != nil {
		fmt.Println(err)
		return
	}
	imageList := []Image{}
	db.Find(&imageList)
	for _, image := range imageList {
		err = GetTokenAndUploadImage(&image)
		if err != nil {
			fmt.Println("上传失败：", err)
		} else {
			fmt.Printf("%s 上传成功\n", image.Url)
			UpdateImageUrl(db, image)
		}
	}
}

func DbImagesToJson() {
	db, err := GetDB()
	if err != nil {
		fmt.Println(err)
		return
	}
	imageList := []Image{}
	db.Find(&imageList)
	raw, err := json.Marshal(imageList)
	if err != nil {
		fmt.Println(err)
	}
	err = ioutil.WriteFile("./data.json", raw, 0644)
	if err != nil {
		fmt.Println(err)
	}
}

func SolveDataJson() {
	fp, err := os.Open("./data.json")
	if err != nil {
		fmt.Println(err)
		return
	}
	raw, err := ioutil.ReadAll(fp)
	if err != nil {
		fmt.Println(err)
		return
	}
	imageList := []Image{}
	err = json.Unmarshal(raw, &imageList)
	if err != nil {
		fmt.Println(err)
		return
	}
	newImageList := []Image{}
	for _, item := range imageList {
		title := item.Title
		if strings.Contains(title, "(") {
			left, right := strings.Index(title, "("), strings.Index(title, ")")
			author := title[left : right+1]
			item.Title = DeleteSpace(title[0:left])
			item.Desc = item.Desc + author
		}
		item.Location = DeleteSpace(item.Location)
		newImageList = append(newImageList, item)
	}
	raw, err = json.Marshal(newImageList)
	if err != nil {
		fmt.Println(err)
		return
	}
	err = ioutil.WriteFile("./data.json", raw, 0644)
	if err != nil {
		fmt.Println(err)
		return
	}
}

func DeleteSpace(src string) string {
	loc := strings.Builder{}
	for _, item := range src {
		if item != ' ' {
			loc.WriteRune(item)
		}
	}
	return loc.String()
}

type FromData struct {
	Url         string `json:"url"`
	Title       string `json:"title"`
	Description string `json:"description"`
	Label       string `json:"label"`
	CreatedBy   int    `json:"createdBy"`
	UpdatedBy   int    `json:"updatedBy"`
}

func InsertImageFromDataJson() {
	fp, err := os.Open("./data.json")
	if err != nil {
		fmt.Println(err)
		return
	}
	raw, err := ioutil.ReadAll(fp)
	if err != nil {
		fmt.Println(err)
		return
	}
	imageList := []Image{}
	err = json.Unmarshal(raw, &imageList)
	if err != nil {
		fmt.Println(err)
		return
	}
	imageList = imageList[26:]
	for _, item := range imageList {
		formData := FromData{
			Url:         item.Url,
			Title:       item.Title,
			Description: item.Desc,
			Label:       item.Location,
			CreatedBy:   1,
			UpdatedBy:   1,
		}
		raw, err = json.Marshal(formData)
		if err != nil {
			fmt.Println(err)
			return
		}
		req, err := http.NewRequest("POST", "http://localhost:7000/image-serv/image", bytes.NewReader(raw))
		if err != nil {
			fmt.Println(err)
			return
		}
		req.Header.Set("Content-Type", "application/json")
		req.Header.Add("Authorization", "Bearer 8bb221d53eb640c29276cd266b615420")
		client := http.Client{}
		res, err := client.Do(req)
		if err != nil {
			fmt.Println(err)
			return
		}
		raw, err = ioutil.ReadAll(res.Body)
		if err != nil {
			fmt.Println(err)
			return
		}
		res.Body.Close()
		fmt.Println(string(raw))
	}
}

func main() {
	InsertImageFromDataJson()
}
